Python 3.9 有什么新变化

您所在的位置:网站首页 python 版本更新 Python 3.9 有什么新变化

Python 3.9 有什么新变化

2024-07-15 01:56| 来源: 网络整理| 查看: 265

Python 3.9 有什么新变化¶ 发布版本

3.9.19

日期

五月 01, 2024

编者

Łukasz Langa

本文介绍了 Python 3.9 相比 3.8 的新特性。 Python 3.9 发布于 2020 年 10 月 5 日。

详情请参阅 更新日志。

参见

PEP 596 - Python 3.9 发布计划

摘要 -- 发布重点¶

新的语法特性:

PEP 584,为 dict 增加合并运算符;

PEP 585,标准多项集中的类型标注泛型。

PEP 614,放宽对装饰器的语法限制。

新的内置特性:

PEP 616,移除前缀和后缀的字符串方法。

标准库中的新特性:

PEP 593,灵活函数和变量注解;

添加了 os.pidfd_open() 以允许不带竞争和信号的进程管理。

解释器的改进:

PEP 573,从 C 扩展类型的方法快速访问模块状态;

PEP 617,CPython 现在使用基于 PEG 的新解析器;

一些 Python 内置类型(range、tuple、set、frozenset、list、dict)现已使用 PEP 590 vectorcall 加速;

垃圾回收不会因恢复的对象而阻塞;

一些 Python 模块(_abc、audioop、_bz2、_codecs、_contextvars、_crypt、_functools、_json、_locale、math、operator、resource、time、_weakref)现已使用 PEP 489 中定义的多段初始化;

一些标准库模块 (audioop、ast、grp、_hashlib、pwd、_posixsubprocess、random、select、struct、termios、zlib) 现已使用 PEP 384 中定义的稳定 ABI。

新的库模块:

PEP 615,标准库的 zoneinfo 模块现已支持 IANA 时区数据库;

图的拓扑排序实现现在已由新的 graphlib 模块提供。

发布进程的变化:

PEP 602,CPython 采用年度发布周期。

请检查代码中的 DeprecationWarning。¶

Python 2.7 支持未终止时,为了实现向下兼容 Python 2.7,Python 3 保留了许多旧版功能。Python 2 的支持终止后,已经移除了一部分向下兼容层,剩余部分很快也会被移除。这几年,大部分兼容层都会触发 DeprecationWarning 警告。例如,2012 年发布 Python 3.3 后,用 collections.Mapping 替代 collections.abc.Mapping 就会触发 DeprecationWarning。

请用 -W default 命令行选项测试应用程序来查看 DeprecationWarning 和 PendingDeprecationWarning,甚至可以用 -W error 将它们视为错误。 可以用 警告过滤器 忽略来自第三方代码的警告。

Python 3.9 是最后一个提供 Python 2 向下兼容层的版本,以给予 Python 项目维护者更多时间移除 Python 2 支持,添加 Python 3.9 支持。

collections 模块中 抽象基类 的别名,例如 collections.abc.Mapping 的别名 collections.Mapping 会为向下兼容最后保留一个发行版。 这些内容将在 Python 3.10 中移除。

更通俗的说法是,请在 Python 开发模式 下运行测试,这样做有助于让代码兼容 Python 的后续版本。

注:一些前期已弃用的内容也将在此 Python 版本中移除。 详见 移除 一节。

新的特性¶ 字典合并与更新运算符¶

合并 (|) 与更新 (|=) 运算符已被加入内置的 dict 类。 它们为现有的 dict.update 和 {**d1, **d2} 字典合并方法提供了补充。

示例:

>>> x = {"key1": "value1 from x", "key2": "value2 from x"} >>> y = {"key2": "value2 from y", "key3": "value3 from y"} >>> x | y {'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'} >>> y | x {'key2': 'value2 from x', 'key3': 'value3 from y', 'key1': 'value1 from x'}

详见 PEP 584。(Brandt Bucher 在 bpo-36144 中的贡献。)

新增用于移除前缀和后缀的字符串方法¶

增加了 str.removeprefix(prefix) 和 str.removesuffix(suffix) 用于方便地从字符串移除不需要的前缀或后缀。 也增加了 bytes, bytearray 以及 collections.UserString 的对应方法。 请参阅 PEP 616 了解详情。 (由 Dennis Sweeney 在 bpo-39939 中贡献。)

标准多项集中的类型标注泛型¶

在类型标注中现在你可以使用内置多项集类型例如 list 和 dict 作为通用类型而不必从 typing 导入对应的大写形式类型名 (例如 List 和 Dict)。 标准库中的其他一些类型现在同样也是通用的,例如 queue.Queue。

示例:

def greet_all(names: list[str]) -> None: for name in names: print("Hello", name)

详见 PEP 585。(由 Guido van Rossum、Ethan Smith 和 Batuhan Taşkaya 在 bpo-39481 中贡献。)

新的解析器¶

Python 3.9 使用于基于 PEG 的新解析器替代 LL(1)。 新解析器的性能与旧解析器大致相当,但 PEG 在设计新语言特性时的形式化比 LL(1) 更灵活。 我们将在 Python 3.10 及之后版本中开始使用这种灵活性。

ast 模块会使用新解析器并会生成与旧解析器一致的 AST。

在 Python 3.10 中,旧解析器将被移除,依赖于它的所有功能也将被移除(主要是 parser 模块,它早已被弃用)。 只有 在 Python 3.9 中,你可以使用命令行开关 (-X oldparser) 或环境变量 (PYTHONOLDPARSER=1) 切换回 LL(1) 解析器。

请参阅 PEP 617 了解详情。 (由 Guido van Rossum, Pablo Galindo 和 Lysandros Nikolaou 在 bpo-40334 中贡献。)

其他语言特性修改¶

__import__() 现在会引发 ImportError 而不是 ValueError,后者曾经会在相对导入超出其最高层级包时发生。 (由 Ngalim Siregar 在 bpo-37444 中贡献。)

Python 现在会获取命令行中指定的脚本文件名 (例如: python3 script.py) 的绝对路径: __main__ 模块的 __file__ 属性将是一个绝对路径,而不是相对路径。 现在此路径在当前目录通过 os.chdir() 被改变后仍将保持有效。 作为附带效果,回溯信息也将在此情况下为 __main__ 模块帧显示绝对路径。 (由 Victor Stinner 在 bpo-20443 中贡献。)

在 Python 开发模式 以及调试编译版本中,现在会针对字符串编码和解码操作检查 encoding 和 errors 参数。 例如: open(), str.encode() 和 bytes.decode()。

默认设置下,为保证性能,errors 参数只会在第一次发生编码/解码错误时被检查,并且对于空字符串 encoding 参数有时会被忽略。 (由 Victor Stinner 在 bpo-37388 中贡献。)

"".replace("", s, n) 对于所有非零的 n 都将返回 s 而不是空字符串。 现在此方法会与 "".replace("", s) 保持一致。 对于 bytes 和 bytearray 对象也有类似的修改。 (由 Serhiy Storchaka 在 bpo-28029 中贡献。)

任何有效的表达式现在都可被用作 decorator。 在之前版本中,相关语法则更为严格。 请参阅 PEP 614 了解详情。 (由 Brandt Bucher 在 bpo-39702 中贡献。)

改进了 typing 模块的帮助信息。 现在将为所有特殊形式和特殊通用别名 (例如 Union 和 List) 显示文档字符串。 使用 help() 时传入通用别名例如 List[int] 将显示对应实体类型 (这里对应的是 list) 的帮助信息。 (由 Serhiy Storchaka 在 bpo-40257 中贡献。)

aclose() / asend() / athrow() 的并行运行现在已被禁止,且 ag_running 现在会反映异步生成器的实际运行状态。 (由 Yury Selivanov 在 bpo-30773 中贡献。)

调用 __iter__ 方法时发生的非预期错误不会再被 in 运算符以及 operator 的 contains(), indexOf() 和 countOf() 中的 TypeError 所掩盖。 (由 Serhiy Storchaka 在 bpo-40824 中贡献。)

未加圆括号的 lambda 表达式不能再作为推导式和生成器表达式的 if 子句的表达式部分。 请参阅 bpo-41848 和 bpo-43755 了解详情。

新增模块¶ zoneinfo¶

zoneinfo 模块为标准库引入了 IANA 时区数据库。 它添加了 zoneinfo.ZoneInfo,这是一个基于系统时区数据的实体 datetime.tzinfo 实现。

示例:

>>> from zoneinfo import ZoneInfo >>> from datetime import datetime, timedelta >>> # Daylight saving time >>> dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles")) >>> print(dt) 2020-10-31 12:00:00-07:00 >>> dt.tzname() 'PDT' >>> # Standard time >>> dt += timedelta(days=7) >>> print(dt) 2020-11-07 12:00:00-08:00 >>> print(dt.tzname()) PST

作为不包含 IANA 数据库的平台的一个回退数据源,还以第一方软件包的形式发布了 tzdata 模块 -- 通过 PyPI 发行并由 CPython 核心团队维护。

参见

PEP 615 -- 在标准库中支持 IANA 时区数据库

PEP 由 Paul Ganssle 撰写并实现

graphlib¶

添加了新的 graphlib 模块,其中包含 graphlib.TopologicalSorter 类来提供图的拓扑排序功能。 (由 Pablo Galindo, Tim Peters 和 Larry Hastings 在 bpo-17005 中贡献。)

改进的模块¶ ast¶

将 indent 选项添加到 dump(),这允许它产生多行缩进的输出。 (由 Serhiy Storchaka 在 bpo-37995 中贡献。)

添加了 ast.unparse() 作为 ast 模块中的一个函数,它可被用来反解析 ast.AST 对象并产生相应的代码字符串,当它被解析时将会产生一个等价的 ast.AST 对象。 (由 Pablo Galindo 和 Batuhan Taskaya 在 bpo-38870 中贡献。)

为 AST 节点添加了文档字符串,其中包含 ASDL 签名,可被用来构造对应的节点。 (由 Batuhan Taskaya 在 bpo-39638 中贡献。)

asyncio¶

出于重要的安全性考量,asyncio.loop.create_datagram_endpoint() 的 reuse_address 形参不再被支持。 这是由 UDP 中的套接字选项 SO_REUSEADDR 的行为导致的。 更多细节请参阅 loop.create_datagram_endpoint() 的文档。 (由 Kyle Stanley, Antoine Pitrou 和 Yury Selivanov 在 bpo-37228 中贡献。。)

添加了新的 coroutine shutdown_default_executor(),它可为等待 ThreadPoolExecutor 结束关闭的默认执行器安排关闭日程操作。 此外,asyncio.run() 已被更新以使用新的 coroutine。 (由 Kyle Stanley 在 bpo-34037 中贡献。)

添加了 asyncio.PidfdChildWatcher,这是一个 Linux 专属的子监视器实现,它负责轮询进程的文件描述符。 (bpo-38692)

添加了新的 coroutine asyncio.to_thread()。 它主要被用于在单独线程中运行 IO 密集型函数以避免阻塞事件循环,实质上就相当于是 run_in_executor() 的高层级版本,可直接接受关键字参数。 (由 Kyle Stanley 和 Yury Selivanov 在 bpo-32309 中贡献。)

当由于超时而取消任务时,asyncio.wait_for() 现在将会等待直到也在 timeout 值 = 0x03090000 // This was not needed before Python 3.9 (Python issue 35810 and 40217) Py_VISIT(Py_TYPE(self)); #endif }

如果你的遍历函数委托给了基类(或其他类)的 tp_traverse,则要确保 Py_TYPE(self) 只被访问一次。 请注意应当只有堆类型可访问 tp_traverse 中的类型。

举例来说,如果你的 tp_traverse 函数包括以下内容:

base->tp_traverse(self, visit, arg)

则要添加:

#if PY_VERSION_HEX >= 0x03090000 // This was not needed before Python 3.9 (Python issue 35810 and 40217) if (base->tp_flags & Py_TPFLAGS_HEAPTYPE) { // a heap type's tp_traverse already visited Py_TYPE(self) } else { Py_VISIT(Py_TYPE(self)); } #else

(参阅 bpo-35810 和 bpo-40217 了解更多信息。)

PyEval_CallObject, PyEval_CallFunction, PyEval_CallMethod 和 PyEval_CallObjectWithKeywords 函数已被弃用。 请改用 PyObject_Call() 及其变化形式。 (详情参见 bpo-29548。)

CPython 字节码的改变¶

添加了 LOAD_ASSERTION_ERROR 操作码用于处理 assert 语句。 在之前的版本中,如果 AssertionError 异常被屏蔽则 assert 语句将不能正常运作。 (由 Zackery Spytz 在 bpo-34880 中贡献。)

COMPARE_OP 操作码已被拆分为四个单独指令:

COMPARE_OP 用于富比较

IS_OP 用于 'is' 和 'is not' 检测

CONTAINS_OP 用于 'in' 和 'not in' 检测

JUMP_IF_NOT_EXC_MATCH 用于检查 'try-except' 语句中的异常。

(由 Mark Shannon 在 bpo-39156 中贡献。)

构建的改变¶

将 --with-platlibdir 选项添加到 configure 脚本:平台专属库目录的名称,保存在新的 sys.platlibdir 属性中。 请参阅 sys.platlibdir 属性了解详情。 (由 Jan Matějek, Matěj Cepl, Charalampos Stratakis 和 Victor Stinner 在 bpo-1294959 中贡献。)

COUNT_ALLOCS 特殊构建宏已被移除。 (由 Victor Stinner 在 bpo-39489 中贡献。)

在非 Windows 平台上,现在需要用 setenv() 和 unsetenv() 函数来构建 Python。 (由 Victor Stinner 在 bpo-39395 中贡献。)

在非 Windows 平台上,创建 bdist_wininst 安装器现在已不受官方支持。 (详情参见 bpo-10945。)

当在 macOS 上用源代码编译 Python 时,_tkinter 现在会链接到非系统的 Tcl 和 Tk 框架,如果它们被安装到 /Library/Frameworks 的话,就如在较旧的 macOS 发行版上的情况一样。 如果通过使用 --enable-universalsdk= 或 -isysroot 明确地配置了 macOS SDK,则只会搜索 SDK 本身。 默认行为仍然可以通过 --with-tcltk-includes 和 --with-tcltk-libs 来覆盖。 (由 Ned Deily 在 bpo-34956 中贡献。)

Python 现在可以针对 Windows 10 ARM64 进行编译。 (由 Steve Dower 在 bpo-33125 中贡献。)

现在当使用 --pgo 时一些单独的测试会被跳过。 这些测试显著增加了 PGO 任务的时间并且可能无助于提升最终可执行文件的优化程度。 这样能使任务加速大约 15 倍。 运行完整的单元测试是很慢的。 这个改变可能导致优化程序稍差的构建,因为将被执行的代码分支不够多。 如果你愿意等待更缓慢的构建,则可以使用 ./configure [..] PROFILE_TASK="-m test --pgo-extended" 来恢复旧版本的行为。 我们不保证哪个 PGO 任务集能产生更快的构建。 关心此问题的用户应当自行运行相关基准测试,因为结果可能取决于具体环境、工作负载以及编译工具链。 (请参阅 bpo-36044 和 bpo-37707 了解详情。)

C API 的改变¶ 新的特性¶

PEP 573: 添加了 PyType_FromModuleAndSpec() 用于通过类来关联一个模块;PyType_GetModule() 和 PyType_GetModuleState() 用于获取模块及其状态;以及 PyCMethod 和 METH_METHOD 用于允许一个方法访问其定义所在的类。 (由 Marcel Plch 和 Petr Viktorin 在 bpo-38787 中贡献。)

增加了 PyFrame_GetCode() 函数:获取帧代码。 增加了 PyFrame_GetBack() 函数:获取帧的下一个外部帧。 (由 Victor Stinner 在 bpo-40421 中贡献。)

将 PyFrame_GetLineNumber() 添加到受限的 C API。 (由 Victor Stinner 在 bpo-40421 中贡献。)

增加了 PyThreadState_GetInterpreter() 和 PyInterpreterState_Get() 函数用于获取解释器。 增加了 PyThreadState_GetFrame() 函数用于获取 Python 线程状态的当前帧。 增加了 PyThreadState_GetID() 函数:获取 Python 线程状态的唯一标识符。 (由 Victor Stinner 在 bpo-39947 中贡献。)

将新的公有 PyObject_CallNoArgs() 函数添加到 C API,该函数可不带任何参数调用一个 Python 可调用对象。 它是不带参数调用 Python 可调用对象最有效率的方式。 (由 Victor Stinner 在 bpo-37194 中贡献。)

受限 C API 中的改变(如果定义了 Py_LIMITED_API 宏):

提供 Py_EnterRecursiveCall() 和 Py_LeaveRecursiveCall() 作为常规函数用于受限 API。 在之前版本中是使用宏定义,但这些宏不能与无法访问 PyThreadState.recursion_depth 字段的受限 C API 一同编译(该结构体在受限 C API 中是不透明的)。

PyObject_INIT() 和 PyObject_INIT_VAR() 已成为常规“不透明”函数以隐藏实现细节。

(由 Victor Stinner 在 bpo-38644 和 bpo-39542 中贡献。)

增加了 PyModule_AddType() 函数以协助将类型加入到模块中。 (由 Dong-hee Na 在 bpo-40024 中贡献。)

将 PyObject_GC_IsTracked() 和 PyObject_GC_IsFinalized() 函数添加到公有 API 以允许分别查询 Python 对象当前是正在被追踪还是已经被垃圾回收器所终结。 (由 Pablo Galindo Salgado 在 bpo-40241 中贡献。)

增加了 _PyObject_FunctionStr() 以获取函数类对象的用户友好的表示形式。 (由 Jeroen Demeyer 在 bpo-37645 中修正。)

增加了 PyObject_CallOneArg() 用于调用具有一个位置参数的对象(由 Jeroen Demeyer 在 bpo-37483 中修正。)

移植到 Python 3.9¶

PyInterpreterState.eval_frame (PEP 523) 现在需要有新的强制性形参 tstate (PyThreadState*)。 (由 Victor Stinner 在 bpo-38500 中贡献。)

扩展模块: PyModuleDef 的 m_traverse, m_clear 和 m_free 等函数在模块状态被请求但尚未被分配时将不会再被调用。 这种情况出现在模块被创建之后且模块被执行 (Py_mod_exec 函数) 之前的时刻。 更准确地说,这些函数在 m_size 大于 0 并且模块状态(即 PyModule_GetState() 的返回值)为 NULL 时将不会被调用。

没有模块状态的扩展模块 (m_size >> from typing import Literal >>> Literal[{0}] >>> Literal[{0}] == Literal[{False}] Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'set'

(由 Yurii Karabas 在 bpo-42345 中贡献。)

macOS 11.0 (Big Sur) 与 Apple Silicon Mac 支持¶

对于 3.9.1 版来说,Python 现在完全支持在 macOS 11.0 (Big Sur) 和 Apple Silicon Macs (基于 ARM64 架构) 上构建和运行。 现在提供了一个新的通用构建类型 universal2,用于在一组可执行文件上原生支持 ARM64 和 Intel 64。 二进制文件现在也可以在当前版本的 macOS 上编译以部署到多种较旧的 macOS 版本上 (已测试 10.9),同时会基于运行时所使用的操作系统版本让某些较新的 OS 功能和选项有条件地可用 ("弱链接") 。

(由 Ronald Oussoren 和 Lawrence D'Anna 在 bpo-41100 中贡献。)

Python 3.9.2 中的重要变化¶ collections.abc¶

现在 collections.abc.Callable 泛型会将类型形参展平,类似于 typing.Callable 当前所做的那样。 这意味着 collections.abc.Callable[[int, str], str] 的 __args__ 将为 (int, str, str);之前则为 ([int, str], str)。 为了允许这个改变,types.GenericAlias 现在可以被子类化,并且在抽取 collections.abc.Callable 类型时将返回一个子类。 通过 typing.get_args() 或 __args__ 访问参数的代码需要考虑到这个改变。 对于无效的 collections.abc.Callable 参数化形式可能会发出 DeprecationWarning,这在 Python 3.9.1 中可能会静默地传递。 这个 DeprecationWarning 将在 Python 3.10 中变为 TypeError。 (由 Ken Jin 在 bpo-42195 中贡献。)

urllib.parse¶

早先的 Python 版本允许使用 ; 和 & 作为 urllib.parse.parse_qs() 和 urllib.parse.parse_qsl() 中 query 形参的分隔键。 出于安全考虑,也为了遵循更新的 W3C 推荐设置,这已被改为只允许单个分隔键,默认为 &。 这一改变还会影响 cgi.parse() 和 cgi.parse_multipart() 因为它们在内部使用了受影响的函数。 要了解更多细节,请查看它们各自的文档。 (由 Adam Goldschmidt, Senthil Kumaran 和 Ken Jin 在 bpo-42967 中贡献。)

Python 3.9.3 中的重要变化¶

新的安全修正将A security fix alters the ftplib.FTP 的行为改成当设置被动数据通道时不信任远程服务器所发送的 IPv4 地址。 我们会改为重用 FTP 服务器的 IP 地址。 对于需要原先行为的不常见代码,请在你的 FTP 实例上设置 trust_server_pasv_ipv4_address 属性为 True。 (参见 bpo-43285)

Python 3.9.5 中的重要变化¶ urllib.parse¶

在 URL 中存在换行符或制表符,可能会导致某些形式的攻击。根据 WHATWG 的规范更新了:rfc:3986, urllib.parse 中的解析器将从 URL 中移除 ASCII 换行符 \n 、\r 和 \t``字符,以防止这种攻击。将移除的字符由一个新的模块级变量``urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE 控制。(参阅 bpo-43882 )

3.9.14 中的重要安全特性¶

使用十进制以外的底,如 2(二进制)、4、8(八进制)、16(十六进制)、32 以外作为基数在 int 和 str 之间进行转换,如果字符串形式的数字数量超过一个限制,会抛出 ValueError,以避免因算法复杂而导致的潜在拒绝服务攻击。这是对 CVE-2020-10735 的缓解方案。这个限制可以通过环境变量、命令行旗标或 sys API 进行配置或禁用。参见 integer string conversion length limitation 文档。默认限制是字符串形式的 4300 位数字。

Notable Changes in 3.9.17¶ tarfile¶

tarfile 中的提取方法和 shutil.unpack_archive() 都新增了 filter 参数以允许限制可能令人意外或危险的 tar 特性,例如在目标目录之外创建文件。 相关细节参见 解压缩过滤器。 在 Python 3.12 中,不带 filter 参数的用法将显示 DeprecationWarning。 在 Python 3.14 中,默认值将切换为 'data'。 (由 Petr Viktorin 在 PEP 706 中贡献。)



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3